package utilities;

import java.util.*;
import java.sql.Connection;

/**
 * Created with IntelliJ IDEA.
 * User: Jordi
 * Date: 29/12/12
 * Time: 19:07
 * To change this template use File | Settings | File Templates.
 */
public class GestorClausPrimaries {

    private GestorClausPrimaries() {
        if (Boolean.getBoolean("debug-lwpf") || Boolean.getBoolean("debug-" + getClass().getName())){
            setDebug(true);
        }
    }
    private static GestorClausPrimaries instancia = null;
    /* Clave por cada tabla */
    protected Map pkCache = new HashMap();
    protected boolean debug = false;
    private static final String DOT = ".";
    public static GestorClausPrimaries getInstance() {
        if (instancia == null) {
            instancia = new GestorClausPrimaries();
        }
        return instancia;
    }
    /*
    * Este método permite poner columnas para una tabla de PrimaryKey
    * sin conexión a la base de datos, etcétera.
    *
    * Asegurese de usar el formato: catalogo + DOT + esquema + DOT + tabla + DOT + columna
    * o bien el formato: esquema + DOT + tabla + DOT + columna
    */
    public synchronized void setPrimaryKey(String catalogo, String esquema, String tabla, List pk){
        String tablaId = null;
        if (catalogo != null && catalogo.trim().length() != 0){
            tablaId = catalogo + DOT + esquema + DOT + tabla;
        }else if (esquema != null && esquema.trim().length() != 0){
            tablaId = esquema + DOT + tabla;
        }else if (tabla != null && tabla.trim().length() != 0){
            tablaId = tabla;
        }else{
            throw new IllegalArgumentException("setPrimaryKey(): desaparecidos todos los identificadores de tabla");
        }
        if (pk == null || pk.size() == 0){
            throw new IllegalArgumentException("setPrimaryKey(): la lista de PK esta vacia");
        }
        if (debug) System.out.println("lwpf ============ " + new Date() + " " + this.getClass() + "::" + this +"::setPrimaryKey()::tablaId: " + tablaId + "                pk: " + pk);
        pkCache.put(tablaId, pk);
    }
    public synchronized List getPrimaryKey(String catalogo, String esquema, String tabla){
        if (debug) System.out.println("lwpf ============ " + new Date() + " " + this.getClass() + "::" + this +"::getPrimaryKey()::catalogo: " + catalogo
                + "::esquema: " + esquema + "::tabla: " + tabla);
        String tablaId = null;
//Build tabla id
        if (catalogo != null && catalogo.trim().length() != 0){
            tablaId = catalogo.trim() + DOT + esquema.trim() + DOT + tabla.trim();
        }else if (esquema != null && esquema.trim().length() != 0){
            tablaId = esquema.trim() + DOT + tabla.trim();
        }else if (tabla != null && tabla.trim().length() != 0){
            tablaId = tabla.trim();
        }else{
            throw new IllegalArgumentException("getPrimaryKey(): Todos los identificadores de tabla han desaparecido");
        }
        if(this.pkCache.containsKey(tablaId)){
            return (List) this.pkCache.get(tablaId); //ya está almacenado (caché)
        }else{
            return null;
        }
    }
    public synchronized List getPrimaryKey(Connection conexion, String catalogo, String esquema, String tabla){
        if (debug) System.out.println("lwpf ============ " + new Date() + " " + this.getClass() + "::" + this +"::getPrimaryKey()::catalogo: " + catalogo
                + "::esquema: " + esquema + "::tabla: " + tabla);
        String tablaId = null;
//Build tabla id
        if (catalogo != null && catalogo.trim().length() != 0){
            tablaId = catalogo.trim() + DOT + esquema.trim() + DOT + tabla.trim();
        }else if (esquema != null && esquema.trim().length() != 0){
            tablaId = esquema.trim() + DOT + tabla.trim();
        }else if (tabla != null && tabla.trim().length() != 0){
            tablaId = tabla.trim();
        }else{
            throw new IllegalArgumentException("getPrimaryKey(): Todos los identificadores de tabla han desaparecido");
        }
        List pkCampos = (List) this.pkCache.get(tablaId);
        if (debug) System.out.println("lwpf ============ " + new Date() + " " + this.getClass() + "::" + this +"::getPrimaryKey()::tablaId: " + tablaId + "                pkFields: " + pkCampos);
        if (pkCampos != null) {
            return pkCampos; //ya está almacenado (caché)
        }else{
            pkCampos = new ArrayList();
        }
        java.sql.ResultSet pkInfo = null;
        try{
            java.sql.DatabaseMetaData dbmd = conexion.getMetaData();
            if (debug) System.out.println("lwpf ============ " + new Date() + " " + this.getClass() + "::" + this
                    +"::getPrimaryKey()::DatabaseMetaData: " + dbmd.getDatabaseProductName() + "::catalogo: " + catalogo + "::esquema: " + esquema + "::tabla: " +
                    tabla);
            pkInfo = dbmd.getPrimaryKeys(catalogo, esquema, tabla);
            if (debug) System.out.println("lwpf ============ " + new Date() + " " + this.getClass() + "::" + this +"::getPrimaryKey()::pkInfo: " + pkInfo);
            while(pkInfo.next()){
                if (debug) System.out.println("lwpf ============ " + new Date() + " " + this.getClass() + "::" + this +"::getPrimaryKey()::pkInfo.next()");
                String nombreColumna = pkInfo.getString(4);
                pkCampos.add(tablaId + DOT + nombreColumna);
            }
            if (debug) System.out.println("lwpf ============ " + new Date() + " " + this.getClass() + "::" + this +"::getPrimaryKey()::pkCampos: " +
                    pkCampos);
            if (pkCampos.isEmpty()){
                throw new java.sql.SQLException("No se puede recuperar informacion de la PrimaryKey desde DatabaseMetaData");
            }
        }catch (java.sql.SQLException sqle){
            throw new RuntimeException(sqle);
        }catch (Exception e){
            throw new RuntimeException(e);
        }finally{
            try{
                if (pkInfo != null) pkInfo.close();
            }catch (java.sql.SQLException sqle){
                sqle.printStackTrace();
                throw new RuntimeException(sqle);
            }
        }
        pkCache.put(tablaId, pkCampos);
        return pkCampos;
    }
    public boolean isDebug() {
        return debug;
    }
    public void setDebug(boolean debug) {
        this.debug = debug;
    }
}
